import { Engine } from "../../Engine";
import { guid } from "../../core/utils";
import { MergeSample } from "./compute/MergeSample";
class Pass {
  static _instance = null;
  constructor() {
    this._swap = 0;
    this.swapAttach = [
    ];
    this._depthAttach = undefined;
    // this._positionAttach = undefined;
    this._pickAttach = undefined;
    this.dirtyAttach = [];
    this.mergeSample = new MergeSample()
  }
  reset() {
    this._swap = 0;
    this.step = 0;
  }
  swap() {//交换附件，read变为write
    this._swap = this._swap ^ 1;
  }
  static instance() {
    if (!Pass._instance) {
      Pass._instance = new Pass();
    }
    return Pass._instance;
  }
  get readAttach() {
    const swap = this._swap;
    let attach = this.swapAttach[swap];
    let sampleCount = 1;
    // if (this.step == 1) {
    //   sampleCount = Engine.instance.multisample ? 4 : 1;
    // }
    if (!attach) {
      attach = Engine.instance.device.createTexture({
        label: "swap",
        size: Engine.instance.size,
        format: Engine.instance.format,
        mipLevelCount: 1,
        sampleCount,
        usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
      });
      attach.view = attach.createView({ label: "read" });
      attach.id = guid();
      this.swapAttach[swap] = attach;
    } else if (attach.width !== Engine.instance.size[0] || attach.height !== Engine.instance.size[1] || attach.sampleCount != sampleCount) {
      this.addDirty(attach);
      attach = Engine.instance.device.createTexture({
        label: "swap",
        size: Engine.instance.size,
        format: Engine.instance.format,
        sampleCount,
        usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
      });
      attach.id = guid();
      attach.view = attach.createView();
      this.swapAttach[swap] = attach;
    }
    return attach;
  }
  get colorTexture() {
    if (!this._colorTexture) {
      this._colorTexture = Engine.instance.device.createTexture({
        label: "color",
        size: Engine.instance.size,
        format: Engine.instance.format,
        mipLevelCount: 1,
        sampleCount: Engine.instance.multisample ? 4 : 1,
        usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
      });
      this._colorTexture.view = this._colorTexture.createView({ label: "read" });
      this._colorTexture.id = guid();
    } else if (this._colorTexture.width !== Engine.instance.size[0] || this._colorTexture.height !== Engine.instance.size[1]) {
      this.addDirty(this._colorTexture);
      this._colorTexture = Engine.instance.device.createTexture({
        label: "color",
        size: Engine.instance.size,
        format: Engine.instance.format,
        sampleCount: Engine.instance.multisample ? 4 : 1,
        usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
      });
      this._colorTexture.id = guid();
      this._colorTexture.view = this._colorTexture.createView();
    }
    return this._colorTexture;
  }
  get writeAttach() {
    const swap = this._swap ^ 1;
    let attach = this.swapAttach[swap];
    let sampleCount = 1;
    // if (this.step == 0) {
    //   sampleCount = Engine.instance.multisample ? 4 : 1;
    // }
    if (!attach) {
      attach = Engine.instance.device.createTexture({
        label: "color",
        size: Engine.instance.size,
        format: Engine.instance.format,
        mipLevelCount: 1,
        sampleCount,
        usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
      });
      attach.view = attach.createView({ label: "write" });
      attach.id = guid();
      this.swapAttach[swap] = attach;
    } else if (attach.width !== Engine.instance.size[0] || attach.height !== Engine.instance.size[1] || attach.sampleCount != sampleCount) {
      this.addDirty(attach);
      attach = Engine.instance.device.createTexture({
        label: "color",
        size: Engine.instance.size,
        format: Engine.instance.format,
        sampleCount,
        usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
      });
      attach.view = attach.createView();
      attach.id = guid();
      this.swapAttach[swap] = attach;
    }
    return attach;
  }
  set writeAttach(v) {
    const swap = this._swap ^ 1;
    this.swapAttach[swap] = v;
  }
  get depthAttach() {
    if (!this._depthAttach) {
      this._depthAttach = Engine.instance.device.createTexture({
        label: "depth",
        size: Engine.instance.size,
        format: 'depth24plus-stencil8',
        sampleCount: Engine.instance.multisample ? 4 : 1,
        usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
      });
      this._depthAttach.view = this._depthAttach.createView();
    } else if (this._depthAttach.width !== Engine.instance.size[0] || this._depthAttach.height !== Engine.instance.size[1]) {
      this.addDirty(this._depthAttach);
      this._depthAttach = Engine.instance.device.createTexture({
        label: "depth",
        size: Engine.instance.size,
        format: 'depth24plus-stencil8',
        sampleCount: Engine.instance.multisample ? 4 : 1,
        usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
      });
      this._depthAttach.view = this._depthAttach.createView();
    }
    return this._depthAttach;
  }
  set depthAttach(v) {
    this._depthAttach = v
  }
  get depthTexture() {
    if (!this._depthTexture) {
      this._depthTexture = Engine.instance.device.createTexture({
        label: "depth",
        size: Engine.instance.size,
        format: "depth24plus-stencil8",
        mipLevelCount: 1,
        sampleCount: 1,
        usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
      });
      this._depthTexture.id = guid();
      this._depthTexture.view = this._depthTexture.createView();
    } else if (this._depthTexture.width !== Engine.instance.size[0] || this._depthTexture.height !== Engine.instance.size[1]) {
      this.addDirty(this._depthTexture);
      this._depthTexture = Engine.instance.device.createTexture({
        label: "depth",
        size: Engine.instance.size,
        format: "depth24plus-stencil8",
        mipLevelCount: 1,
        sampleCount: 1,
        usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
      });
      this._depthTexture.id = guid();
      this._depthTexture.view = this._depthTexture.createView();
    }
    return this._depthTexture;
  }
  set depthTexture(v) {
    if (this._depthTexture && this._depthTexture.id != v.id) {
      this.addDirty(this._depthTexture);
    }
    this._depthTexture = v
  }
  get postionAttach() {
    if (!this._postionAttach) {
      this._postionAttach = Engine.instance.device.createTexture({
        label: "position",
        size: Engine.instance.size,
        format: "rgba16float",
        mipLevelCount: 1,
        sampleCount: Engine.instance.multisample ? 4 : 1,
        usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
      });
      this._postionAttach.id = guid();
      this._postionAttach.view = this._postionAttach.createView();
    } else if (this._postionAttach.width !== Engine.instance.size[0] || this._postionAttach.height !== Engine.instance.size[1]) {
      this.addDirty(this._postionAttach);
      this._postionAttach = Engine.instance.device.createTexture({
        label: "position",
        size: Engine.instance.size,
        format: "rgba16float",
        mipLevelCount: 1,
        sampleCount: Engine.instance.multisample ? 4 : 1,
        usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
      });
      this._postionAttach.id = guid();
      this._postionAttach.view = this._postionAttach.createView();
    }
    return this._postionAttach;
  }
  get postionTexture() {
    if (!this._postionTexture) {
      this._postionTexture = Engine.instance.device.createTexture({
        label: "position",
        size: Engine.instance.size,
        format: "rgba16float",
        mipLevelCount: 1,
        sampleCount: 1,
        usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
      });
      this._postionTexture.id = guid();
      this._postionTexture.view = this._postionTexture.createView();
    } else if (this._postionTexture.width !== Engine.instance.size[0] || this._postionTexture.height !== Engine.instance.size[1]) {
      this.addDirty(this._postionTexture);
      this._postionTexture = Engine.instance.device.createTexture({
        label: "position",
        size: Engine.instance.size,
        format: "rgba16float",
        mipLevelCount: 1,
        sampleCount: 1,
        usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
      });
      this._postionTexture.id = guid();
      this._postionTexture.view = this._postionTexture.createView();
    }
    return this._postionTexture;
  }
  set postionTexture(v) {
    if (this._postionTexture && this._postionTexture.id != v.id) {
      this.addDirty(this._postionTexture);
    }
    this._postionTexture = v
  }
  get normalAttach() {
    if (!this._normalAttach) {
      this._normalAttach = Engine.instance.device.createTexture({
        label: "normal",
        size: Engine.instance.size,
        format: "rgba16float",
        mipLevelCount: 1,
        sampleCount: Engine.instance.multisample ? 4 : 1,
        usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
      });
      this._normalAttach.id = guid();
      this._normalAttach.view = this._normalAttach.createView();
    } else if (this._normalAttach.width !== Engine.instance.size[0] || this._normalAttach.height !== Engine.instance.size[1]) {
      this.addDirty(this._normalAttach);
      this._normalAttach = Engine.instance.device.createTexture({
        label: "normal",
        size: Engine.instance.size,
        format: "rgba16float",
        mipLevelCount: 1,
        sampleCount: Engine.instance.multisample ? 4 : 1,
        usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
      });
      this._normalAttach.id = guid();
      this._normalAttach.view = this._normalAttach.createView();
    }
    return this._normalAttach;
  }
  get normalTexture() {
    if (!this._normalTexture) {
      this._normalTexture = Engine.instance.device.createTexture({
        label: "normal",
        size: Engine.instance.size,
        format: "rgba16float",
        mipLevelCount: 1,
        sampleCount: 1,
        usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
      });
      this._normalTexture.id = guid();
      this._normalTexture.view = this._normalTexture.createView();
    } else if (this._normalTexture.width !== Engine.instance.size[0] || this._normalTexture.height !== Engine.instance.size[1]) {
      this.addDirty(this._normalTexture);
      this._normalTexture = Engine.instance.device.createTexture({
        label: "normal",
        size: Engine.instance.size,
        format: "rgba16float",
        mipLevelCount: 1,
        sampleCount: 1,
        usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
      });
      this._normalTexture.id = guid();
      this._normalTexture.view = this._normalTexture.createView();
    }
    return this._normalTexture;
  }
  set normalTexture(v) {
    if (this._normalTexture && this._normalTexture.id != v.id) {
      this.addDirty(this._normalTexture);
    }
    this._normalTexture = v
  }
  addDirty(attach) {
    this.dirtyAttach.push(attach);
  }
  clearDirty() {
    for (let i = 0; i < this.dirtyAttach.length; i++) {
      this.dirtyAttach[i].destroy();
    }
    this.dirtyAttach = [];
  }
  get pickAttach() {
    if (!this._pickAttach) {
      this._pickAttach = Engine.instance.device.createTexture({
        label: "pick",
        size: Engine.instance.size,
        format: Engine.instance.format,
        mipLevelCount: 1,
        sampleCount: Engine.instance.multisample ? 4 : 1,
        usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
      });
      this._pickAttach.id = guid();
      this._pickAttach.view = this._pickAttach.createView();
    } else if (this._pickAttach.width !== Engine.instance.size[0] || this._pickAttach.height !== Engine.instance.size[1]) {
      this.addDirty(this._pickAttach);
      this._pickAttach = Engine.instance.device.createTexture({
        label: "pick",
        size: Engine.instance.size,
        format: Engine.instance.format,
        mipLevelCount: 1,
        sampleCount: Engine.instance.multisample ? 4 : 1,
        usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
      });
      this._pickAttach.id = guid();
      this._pickAttach.view = this._pickAttach.createView();
    }
    return this._pickAttach;
  }
  get pickTexture() {
    if (!this._pickTexture) {
      this._pickTexture = Engine.instance.device.createTexture({
        label: "pick",
        size: Engine.instance.size,
        format: Engine.instance.format,
        mipLevelCount: 1,
        sampleCount: 1,
        usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
      });
      this._pickTexture.id = guid();
      this._pickTexture.view = this._pickTexture.createView();
    } else if (this._pickTexture.width !== Engine.instance.size[0] || this._pickTexture.height !== Engine.instance.size[1]) {
      this.addDirty(this._pickTexture);
      this._pickTexture = Engine.instance.device.createTexture({
        label: "pick",
        size: Engine.instance.size,
        format: Engine.instance.format,
        mipLevelCount: 1,
        sampleCount: 1,
        usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
      });
      this._pickTexture.id = guid();
      this._pickTexture.view = this._pickTexture.createView();
    }
    return this._pickTexture;
  }
  set pickTexture(v) {
    if (this._pickTexture && this._pickTexture.id != v.id) {
      this.addDirty(this._pickTexture);
    }
    this._pickTexture = v
  }
  destroy() {
    if (this.swapAttach[0]) {
      this.swapAttach[0].destroy();
    }
    if (this.swapAttach[1]) {
      this.swapAttach[1].destroy();
    }
    if (this._pickAttach) {
      this._pickAttach.destroy();
    }
    if (this._depthAttach) {
      this._depthAttach.destroy();
    }
    if (this._postionTexture) {
      this._postionTexture.destroy();
    }
    if (this._normalTexture) {
      this._normalTexture.destroy();
    }
    Pass._instance = null;
  }
  // 添加获取发光附件的方法
  getShineAttachments() {
    // 检查是否需要重新创建附件
    if (!this.shineAttachments ||
        this.shineAttachments.width !== Engine.instance.size[0] ||
        this.shineAttachments.height !== Engine.instance.size[1]) {
      // 创建发光颜色附件
      this.shineAttachments = Engine.instance.device.createTexture({
        size: [Engine.instance.size[0], Engine.instance.size[1]],
        format: Engine.instance.format,
        sampleCount: 1,
        usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING
      });
      this.shineAttachments.view=this.shineAttachments.createView({label:"shineAttachments",});
    }
    return this.shineAttachments;
  }
}
export { Pass }
